import asyncio
import cv2
import sys
import time
from av import VideoFrame
import fractions
import os

from aiortc_custom import VideoStreamTrack
from LocalVideoPlayer import LocalVideoPlayer


class TimedVideoStreamTrack(VideoStreamTrack):
    def __init__(self, video_source, preview_manager=None):
        super().__init__()
        self.video_source = video_source
        self.cap = None
        self.frame_count = 0
        self.last_capture_time = 0
        # 采集/驱动缓冲时延与前处理时延统计
        self.capture_delays = []  # 采集/驱动缓冲时延（ms）
        self.frame_prep_delays = []  # 前处理时延（ms）
        self.last_stats_time = time.time()  # 上次统计时间
        self.stats_interval = 1.0  # 统计间隔（秒）
        self.preview_manager = preview_manager
        self.fps = 25  # 默认25fps
        self.frame_delay = 1.0 / self.fps  # 帧间隔时间
        self.is_camera = False  # 标记是否为摄像头
        self.camera_retry_count = 0  # 摄像头重试次数
        self.max_camera_retries = 3  # 最大重试次数
        self._capture_t0 = None  # 首帧基准时间（monotonic），用于估算期望时间戳
        self._wall_t0 = None  # 文件源播放的墙钟基准（monotonic）

        # 本地FFmpeg播放器
        self.local_video_player = None
        self.player_initialized = False

        # 初始化视频源
        self._init_video_source()

        # 初始化本地预览窗口
        self._init_local_preview()
        
    def _init_video_source(self):
        """初始化视频源（摄像头或视频文件）"""
        # 检查是否为摄像头ID（数字）
        if isinstance(self.video_source, int) or (isinstance(self.video_source, str) and self.video_source.isdigit()):
            # 使用摄像头
            camera_id = int(self.video_source)
            self._init_camera(camera_id)
        else:
            # 使用视频文件
            self._init_video_file()
    
    def _init_camera(self, camera_id):
        """初始化摄像头"""
        try:
            print(f"正在初始化摄像头 ID: {camera_id}...")
            
            # 尝试不同的摄像头初始化方式
            if sys.platform == "linux":
                # Linux下优先使用V4L2
                self.cap = cv2.VideoCapture(camera_id, cv2.CAP_V4L2)
                if not self.cap.isOpened():
                    print(f"V4L2初始化失败，尝试默认方式...")
                    self.cap = cv2.VideoCapture(camera_id)
            else:
                # Windows下使用默认方式
                self.cap = cv2.VideoCapture(camera_id)
            
            if not self.cap.isOpened():
                raise RuntimeError(f"无法打开摄像头 ID: {camera_id}")
            
            # 设置摄像头参数
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
            self.cap.set(cv2.CAP_PROP_FPS, 25)
            self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)  # 减少缓冲延迟
            
            # 获取实际设置的值
            self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            self.fps = self.cap.get(cv2.CAP_PROP_FPS)
            if self.fps <= 0:
                self.fps = 25
            self.frame_delay = 1.0 / self.fps
            
            # 测试读取一帧确保摄像头工作正常
            ret, test_frame = self.cap.read()
            if not ret or test_frame is None:
                raise RuntimeError("摄像头无法读取帧")
            
            self.is_camera = True
            print(f"✓ 已成功连接摄像头 ID: {camera_id}")
            print(f"摄像头分辨率: {self.width}x{self.height}")
            print(f"摄像头帧率: {self.fps:.2f} fps")
            print(f"帧间隔: {self.frame_delay*1000:.2f} ms")
            
        except Exception as e:
            print(f"✗ 摄像头初始化失败: {e}")
            self.camera_retry_count += 1
            
            if self.camera_retry_count < self.max_camera_retries:
                print(f"尝试重新初始化摄像头 (第 {self.camera_retry_count} 次重试)...")
                time.sleep(1)  # 等待1秒后重试
                self._init_camera(camera_id)
            else:
                print("摄像头初始化失败次数过多，将自动切换到本地视频文件模式")
                self._init_video_file()
    
    def _init_video_file(self):
        """初始化视频文件"""
        # 默认视频文件路径
        default_video_path = "time.mp4"
        
        # 如果video_source是文件路径且存在，使用它；否则使用默认文件
        if isinstance(self.video_source, str) and os.path.exists(self.video_source):
            video_path = self.video_source
        elif os.path.exists(default_video_path):
            video_path = default_video_path
        else:
            raise FileNotFoundError(f"未找到视频文件: {self.video_source} 或 {default_video_path}")
            
        self.cap = cv2.VideoCapture(video_path)
        if not self.cap.isOpened():
            raise RuntimeError(f"无法打开视频文件: {video_path}")
            
        # 获取视频属性
        self.fps = self.cap.get(cv2.CAP_PROP_FPS)
        if self.fps <= 0:
            self.fps = 25  # 如果无法获取fps，使用默认值
        self.frame_delay = 1.0 / self.fps
        
        # 获取视频尺寸
        self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        
        self.is_camera = False
        print(f"✓ 使用视频文件: {video_path}")
        print(f"视频尺寸: {self.width}x{self.height}")
        print(f"视频帧率: {self.fps:.2f} fps")
        print(f"帧间隔: {self.frame_delay*1000:.2f} ms")

    def _init_local_preview(self):
        """初始化本地预览窗口 - 使用FFmpeg统一播放"""
        try:
            source_type = "摄像头" if self.is_camera else "视频文件"
            self.local_video_player = LocalVideoPlayer(
                window_title=f"WebRTC本地{source_type}",
                width=640,
                height=480
            )
            success = self.local_video_player.start(width=640, height=480, fps=int(self.fps))
            if success:
                self.player_initialized = True
                print(f"✓ 已使用FFmpeg初始化本地{source_type}播放器")
            else:
                print(f"✗ FFmpeg本地播放器启动失败，将不显示本地预览")
                self.local_video_player = None
        except Exception as e:
            print(f"✗ 初始化本地FFmpeg播放器失败: {e}")
            self.local_video_player = None

    async def recv(self):
        try:
            if self.cap is None:
                print("视频捕获器未初始化")
                await asyncio.sleep(self.frame_delay)
                return None
            
            # 读取原始帧（采集）
            read_start = time.perf_counter()
            ret, frame = self.cap.read()
            read_end = time.perf_counter()
            if not ret:
                if self.is_camera:
                    # 摄像头读取失败，尝试重新初始化
                    print("从摄像头读取帧失败，尝试重新初始化...")
                    self.cap.release()
                    self.cap = None
                    self._init_camera(int(self.video_source))
                    if self.cap is None:
                        print("摄像头重新初始化失败")
                        await asyncio.sleep(self.frame_delay)
                        return None
                    # 重新尝试读取
                    ret, frame = self.cap.read()
                    if not ret:
                        print("摄像头重新初始化后仍无法读取帧")
                        await asyncio.sleep(self.frame_delay)
                        return None
                else:
                    # 视频播放完毕，重新开始播放
                    print("视频播放完毕，重新开始播放...")
                    self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
                    ret, frame = self.cap.read()
                    if not ret:
                        print("重新播放失败")
                        await asyncio.sleep(self.frame_delay)
                        return None
            if frame is not None:
                # 统计采集/驱动缓冲时延
                capture_delay_ms = (read_end - read_start) * 1000.0
                self.capture_delays.append(max(0.0, capture_delay_ms))

                self.frame_count += 1
                
                # 帧准备开始时间
                frame_prep_start = time.perf_counter()
                
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                video_frame = VideoFrame.from_ndarray(frame_rgb, format='rgb24')
                video_frame.pts = self.frame_count
                video_frame.time_base = fractions.Fraction(1, int(self.fps))
                
                # 帧准备结束时间
                frame_prep_end = time.perf_counter()
                frame_prep_delay = (frame_prep_end - frame_prep_start) * 1000
               
                self.frame_prep_delays.append(frame_prep_delay)
                
                # 每秒更新一次统计信息
                current_time = time.time()
                if current_time - self.last_stats_time >= self.stats_interval:
                    # 计算过去一秒内的平均采集/驱动缓冲与前处理时延
                    avg_cap = (sum(self.capture_delays) / len(self.capture_delays)) if self.capture_delays else 0.0
                    avg_prep = (sum(self.frame_prep_delays) / len(self.frame_prep_delays)) if self.frame_prep_delays else 0.0
                    window_frames = max(len(self.frame_prep_delays), len(self.capture_delays))
                    source_type = "摄像头" if self.is_camera else "视频文件"
                    print(f"发送侧[{source_type}] 采集/驱动缓冲时延: {avg_cap:.2f} ms, 前处理时延: {avg_prep:.2f} ms (1s, {window_frames} 帧)")
                        
                    # 清空时延数据，准备下一秒的统计
                    self.capture_delays.clear()
                    self.frame_prep_delays.clear()
                    self.last_stats_time = current_time
                
                # 显示本地视频预览
                self._show_local_preview(frame)
                    
                # 控制帧率，确保按视频原始帧率发送
                await asyncio.sleep(self.frame_delay)
                    
                return video_frame
        except Exception as e:
            print(f"recv异常: {e}")
            await asyncio.sleep(self.frame_delay)
            return None

    def _show_local_preview(self, frame):
        """显示本地视频预览 - 使用FFmpeg播放"""
        try:
            # 使用FFmpeg本地播放器统一显示
            if self.local_video_player and self.player_initialized:
                self.local_video_player.write_frame(frame)
            # 后备方案：如果FFmpeg播放器未初始化，尝试使用preview_manager
            elif self.preview_manager:
                self.preview_manager.update_frame(frame, "local")
        except Exception as e:
            import traceback
            print(f"显示本地预览失败: {e}")
            traceback.print_exc()
            
    def __del__(self):
        """析构函数，确保释放资源"""
        # 清理本地视频播放器
        if self.local_video_player:
            try:
                self.local_video_player.stop()
            except Exception:
                pass

        # 清理视频捕获器
        if self.cap:
            self.cap.release()